package com.devbobcorn.nekoration.client.rendering.blockentities;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

import com.devbobcorn.nekoration.blocks.entities.PrismapTableBlockEntity;
import com.devbobcorn.nekoration.client.rendering.ChunkModel;
import com.devbobcorn.nekoration.client.rendering.chunks.ChunkModelRender;
import com.mojang.blaze3d.matrix.MatrixStack;
import com.mojang.blaze3d.platform.GlStateManager;

import org.lwjgl.opengl.GL11;

import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.WorldRenderer;
import net.minecraft.client.renderer.texture.AtlasTexture;
import net.minecraft.client.renderer.tileentity.TileEntityRenderer;
import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.client.renderer.vertex.VertexBuffer;
import net.minecraft.util.math.BlockPos;
import net.minecraftforge.fml.common.ObfuscationReflectionHelper;

public class PrismapTableRenderer extends TileEntityRenderer<PrismapTableBlockEntity> {
    private static Minecraft mc = null;
	public static Method MRenderWorld = null;
	public static Class<?> CLocalRenderInfoContainer = null;
	public static Field FChunk = null;
	public static Field FRenderChunkLayer = null;
	private static boolean error = false;

	public PrismapTableRenderer(TileEntityRendererDispatcher tileEntityRendererDispatcher) {
		super(tileEntityRendererDispatcher);
	}

    @SuppressWarnings("deprecation")
	public void render(PrismapTableBlockEntity tileEntity, float partialTicks, MatrixStack stack, IRenderTypeBuffer buffers, int combinedLight, int combinedOverlay) {
		if (mc == null)
			mc = Minecraft.getInstance();

		if (!error)
			if (MRenderWorld == null)
				hackItUp();
			else {
				try {
					final ChunkModel miniModel = tileEntity.chunkModel;

					if (miniModel == null)
						return;
			
					if (!miniModel.isCompiled() && !miniModel.getError())
						miniModel.compile();
					
					// Render the world...
					BlockPos pos = tileEntity.getBlockPos();
					double x = pos.getX();
					double y = pos.getY();
					double z = pos.getZ();
					stack.translate(0.0, 0.75, 0.0);
					stack.scale(0.0625F, 0.0625F, 0.0625F);
					renderModelChunkLayer(RenderType.solid(), stack, miniModel.chunkRender, x, y, z);
					mc.getModelManager().getAtlas(AtlasTexture.LOCATION_BLOCKS).setBlurMipmap(false, mc.options.mipmapLevels > 0); // FORGE: fix flickering leaves when mods mess up the blurMipmap settings
					renderModelChunkLayer(RenderType.cutoutMipped(), stack, miniModel.chunkRender, x, y, z);
					mc.getModelManager().getAtlas(AtlasTexture.LOCATION_BLOCKS).restoreLastBlurMipmap();
					renderModelChunkLayer(RenderType.cutout(), stack, miniModel.chunkRender, x, y, z);

					//MRenderWorld.invoke(mc.levelRenderer, RenderType.solid(), stack, x, y, z); Or call vanilla WorldRenderer's method to do the rendering (Blend options not customizable)
				} catch (Exception e) {
					error = true;
					e.printStackTrace();
				}
			}
	}

	/* private void renderWorldChunkLayer(RenderType type, MatrixStack stack, double x, double y, double z) {
		type.setupRenderState();
		boolean flag = type != RenderType.translucent();
		try {
			ObjectList<?> chunkList = (ObjectList<?>) FRenderChunkLayer.get(mc.levelRenderer);
			ObjectListIterator<?> iterator = chunkList.listIterator(flag ? 0 : chunkList.size());
			while (true) {
				if (flag) {
					if (!iterator.hasNext()) {
						break;
					}
				} else if (!iterator.hasPrevious()) {
					break;
				}
				Object container = (flag ? iterator.next() : iterator.previous());
				if (CLocalRenderInfoContainer == null){
					CLocalRenderInfoContainer = container.getClass();
					System.out.println("Clazz: " + CLocalRenderInfoContainer);
					if (FChunk == null){
						FChunk = ObfuscationReflectionHelper.findField(CLocalRenderInfoContainer, "field_178036_a");
					}
				}
				ChunkRenderDispatcher.ChunkRender chunkrender = (ChunkRenderDispatcher.ChunkRender) FChunk.get(container);
				if (!chunkrender.getCompiledChunk().isEmpty(type)) {
					VertexBuffer vertexbuffer = chunkrender.getBuffer(type);
					stack.pushPose();
					BlockPos blockpos = chunkrender.getOrigin();
					stack.translate((double) blockpos.getX() - x, (double) blockpos.getY() - y, (double) blockpos.getZ() - z);
					vertexbuffer.bind();
					DefaultVertexFormats.BLOCK.setupBufferState(0L);
					// Translucency
					GlStateManager._blendFunc(GL11.GL_ONE, GL11.GL_ONE);
					GlStateManager._enableBlend();
					vertexbuffer.draw(stack.last().pose(), 7);
					stack.popPose();
				}
			}
			VertexBuffer.unbind();
			//RenderSystem.clearCurrentColor();
			DefaultVertexFormats.BLOCK.clearBufferState();
			type.clearRenderState();
		} catch (Exception e) {
			error = true;
			e.printStackTrace();
		}
	} */

	private void renderModelChunkLayer(RenderType type, MatrixStack stack, ChunkModelRender chunkrender, double x, double y, double z) {
		type.setupRenderState();
		try {
			if (!chunkrender.getCompiledChunk().isEmpty(type)) {
				VertexBuffer vertexbuffer = chunkrender.getBuffer(type);
				stack.pushPose();
				//BlockPos blockpos = chunkrender.getOrigin();
				//stack.translate((double) blockpos.getX() - x, (double) blockpos.getY() - y, (double) blockpos.getZ() - z);
				vertexbuffer.bind();
				DefaultVertexFormats.BLOCK.setupBufferState(0L);
				// Translucency
				GlStateManager._blendFunc(GL11.GL_ONE, GL11.GL_ONE);
				GlStateManager._enableBlend();
				vertexbuffer.draw(stack.last().pose(), 7);
				stack.popPose();
			}
			VertexBuffer.unbind();
			//RenderSystem.clearCurrentColor();
			DefaultVertexFormats.BLOCK.clearBufferState();
			type.clearRenderState();
		} catch (Exception e) {
			error = true;
			e.printStackTrace();
		}
	}

	private void hackItUp(){
		try {
			MRenderWorld = ObfuscationReflectionHelper.findMethod(WorldRenderer.class, "func_228441_a_", RenderType.class, MatrixStack.class, double.class, double.class, double.class);
			FRenderChunkLayer = ObfuscationReflectionHelper.findField(WorldRenderer.class, "field_72755_R");
		} catch (Exception e) {
			error = true;
			e.printStackTrace();
		}
	}
}
